#define BOOST_TEST_MODULE testHasChanges

#include <memory>
#include <thread>

#include <boost/test/unit_test.hpp>

#include <crow.h>

#include "common/api/client.h"
#include "common/api/result.hpp"
#include "common/api/server.h"
#include "common/api/server_helper.hpp"

#include "common/elements/element_type.hpp"

#include "common/more/uuid.h"

class Server final
{
public:
    Server()
        : m_crowApplication(new crow::SimpleApp)
    {
        ADD_CROW_ROUTE_HAS_CHANGES(
            (*m_crowApplication),
            [this](const Uuids::Uuid& sessionUuid) -> Api::Changes
            {
                Api::Changes result;
                if (!sessionUuid.is_nil())
                {
                    result[Elements::ElementType::Item] = std::set<unsigned>({ 1, 2 });
                    result[Elements::ElementType::User] = std::set<unsigned>({ 3, 4 });
                }
                return result;
            }
        );
        m_runThread.reset(new std::thread(
            [this]()
            { m_crowApplication->port(8080).multithreaded().run(); }
        ));
        m_stopThread.reset(new std::thread(
            [this]()
            { stop(); }
        ));
    }

    ~Server()
    {
        m_stopThread->join();
        m_runThread->join();
    }

private:
    std::unique_ptr<crow::SimpleApp> m_crowApplication;
    std::unique_ptr<std::thread> m_runThread;
    std::unique_ptr<std::thread> m_stopThread;

    void stop()
    {
        std::this_thread::sleep_for(std::chrono::seconds(2));
        m_crowApplication->stop();
    }
};

Server server;
Api::Client client("http://127.0.0.1:8080");

BOOST_AUTO_TEST_CASE(testCorrectHasChanges)
{
    const Api::Changes result = client.hasChanges(Uuids::newUuid());
    BOOST_CHECK(result.size() == 2);
    BOOST_CHECK(result.count(Elements::ElementType::Item) == 1);
    BOOST_CHECK(result.count(Elements::ElementType::User) == 1);
    BOOST_CHECK(result.at(Elements::ElementType::Item).count(1) == 1);
    BOOST_CHECK(result.at(Elements::ElementType::Item).count(2) == 1);
    BOOST_CHECK(result.at(Elements::ElementType::User).count(3) == 1);
    BOOST_CHECK(result.at(Elements::ElementType::User).count(4) == 1);
}

BOOST_AUTO_TEST_CASE(testNonCorrectHasChanges)
{
    const Api::Changes result = client.hasChanges(Uuids::nilUuid());
    BOOST_CHECK(result.size() == 0);
}
